package com.siashan.toolkit.core.date;

import com.siashan.toolkit.core.util.StrUtil;
import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 日期工具类
 *
 * @author siashan
 * @since v1.0.7
 **/
public class DateUtil {


    //****************************************************** 日期比较 start ********************************************//

    /**
     * 比较两个时间的大小
     *
     * @param date1 日期对象1
     * @param date2 日期对象2
     * @return 比较结果，如果date1 &lt; date2，返回数小于0，date1==date2返回0，date1 &gt; date2 大于0
     */

    public static int compare(Date date1, Date date2) {
        return date1.compareTo(date2);
    }

    /**
     * 比较时间是否小于
     *
     * @param date1 日期对象1
     * @param date2 日期对象2
     * @return 比较结果
     */
    public static boolean isLt(Date date1, Date date2) {
        return compare(date1, date2) < 0;
    }

    /**
     * 比较时间是否大于
     *
     * @param date1 日期对象1
     * @param date2 日期对象2
     * @return 比较结果
     */
    public static boolean isGt(Date date1, Date date2) {
        return compare(date1, date2) > 0;
    }

    /**
     * 比较时间是否相等
     *
     * @param date1 日期对象1
     * @param date2 日期对象2
     * @return 比较结果
     */
    public static boolean isEq(Date date1, Date date2) {
        return compare(date1, date2) == 0;
    }
    //****************************************************** 日期比较 end ********************************************//

    /**
     * 验证字符串是否为指定日期格式
     *
     * @param oriDateStr 待验证字符串
     * @param pattern    日期字符串格式, 例如 "yyyy-MM-dd"
     * @return 有效性结果, true 为正确, false 为错误
     */
    public static boolean dateStrIsValid(String oriDateStr, String pattern) {
        if (StrUtil.isBlank(oriDateStr) || StrUtil.isBlank(pattern)) {
            return false;
        }

        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);

        Date date = null;
        try {
            date = dateFormat.parse(oriDateStr);
            return oriDateStr.equals(dateFormat.format(date));
        } catch (ParseException e) {
            return false;
        }
    }

    /**
     * 格式化日期间隔输出，精确到毫秒
     *
     * @param betweenMs 日期间隔
     * @return XX天XX小时XX分XX秒XX毫秒
     * @since 3.0.1
     */
    public static String formatBetween(long betweenMs) {
        return new BetweenFormatter(betweenMs, BetweenFormatter.Level.MILLISECOND).format();
    }


    /**
     * 获得指定日期是星期几，1表示周日，2表示周一
     *
     * @param date 日期
     * @return 天
     */
    public static int dayOfWeek(Date date) {
        return getField(date, DateField.DAY_OF_WEEK);
    }

    /**
     * 获得指定日期是星期几
     *
     * @param date 日期
     * @return {@link Week}
     */
    public static Week dayOfWeekEnum(Date date) {
        return Week.of(dayOfWeek(date));
    }


    /**
     * 获取两个时间间隔内的所有日期
     *
     * @param startDate 初始日期
     * @param endDate   结束日期
     * @return 日期集合
     */
    public static List<Date> getBetweenDate(Date startDate, Date endDate) {
        return getBetweenDate(startDate, endDate, true, true);
    }

    /**
     * 获取两个时间间隔内的所有日期
     *
     * @param startDate      初始日期
     * @param endDate        结束日期
     * @param isIncludeStart 是否包含初始日期
     * @param isIncludeEnd   是否包含结束日期
     * @return 日期集合
     */
    public static List<Date> getBetweenDate(Date startDate, Date endDate, boolean isIncludeStart, boolean isIncludeEnd) {
        if (null == startDate || null == endDate) {
            throw new IllegalArgumentException("日期不能为空");
        }
        List<Date> list = new ArrayList<Date>();
        // 如果两个日期相等
        if (isEq(startDate, endDate)) {
            if (isIncludeStart && isIncludeStart) {
                list.add(startDate);
            }
        } else {
            if (isLt(startDate, endDate)) {
                while (isLt(startDate, endDate) || isEq(startDate, endDate)) {
                    // 把日期添加到集合
                    list.add(new Date(startDate.getTime()));
                    // 获取增加后的日期
                    startDate = offsetDay(startDate, 1);
                }
            } else {
                while (isGt(startDate, endDate) || isEq(startDate, endDate)) {
                    // 把日期添加到集合
                    list.add(new Date(startDate.getTime()));
                    // 获取增加后的日期
                    startDate = offsetDay(startDate, -1);
                }
            }
            if (!isIncludeStart) {
                list.remove(0);
            }
            if (!isIncludeEnd) {
                list.remove(list.size() - 1);
            }
        }
        return list;
    }


    /**
     * 获取两个时间间隔内的所有指定周几的日期
     *
     * @param dateList 日期集合
     * @param week     周几
     * @return 日期集合
     */
    public static List<Date> getWeekBetweenDate(List<Date> dateList, Week week) {
        List<Date> retList = new ArrayList<>();
        if (null != dateList && !dateList.isEmpty()) {
            for (Date date : dateList) {
                if (week.getValue() == dayOfWeek(date)) {
                    retList.add(date);
                }
            }
        }
        return retList;
    }
//    /**
//     * 获取两个时间间隔内的所有指定周几的日期
//     *
//     * @param startDate      初始日期
//     * @param endDate        结束日期
//     * @return 日期集合
//     */
//    public static List<Date> getWeekBetweenDate(Date startDate, Date endDate, Week week) {
//        return getWeekBetweenDate(startDate,endDate,week,true,true);
//    }

//    /**
//     * 获取两个时间间隔内的所有指定周几的日期
//     *
//     * @param startDate      初始日期
//     * @param endDate        结束日期
//     * @param isIncludeStart 是否包含初始日期
//     * @param isIncludeEnd   是否包含结束日期
//     * @return 日期集合
//     */
//    public static List<Date> getWeekBetweenDate(Date startDate, Date endDate, Week week, boolean isIncludeStart, boolean isIncludeEnd) {
//        if (null == startDate || null == endDate) {
//            throw new IllegalArgumentException("日期不能为空");
//        }
//        List<Date> list = new ArrayList<Date>();
//        // 如果两个日期相等
//        if (isEq(startDate, endDate)) {
//            if (isIncludeStart && isIncludeStart && isWeekMatch(week,startDate)) {
//                list.add(startDate);
//            }
//        } else {
//            if (isLt(startDate, endDate)) {
//                while (isLt(startDate, endDate) || isEq(startDate, endDate)) {
//                    // 把日期添加到集合
//                    Date nDate = new Date(startDate.getTime());
//                    if (isWeekMatch(week,nDate)) {
//                        list.add(nDate);
//                    }
//                    // 获取增加后的日期
//                    startDate = offsetDay(startDate, 1);
//                }
//            } else {
//                while (isGt(startDate, endDate) || isEq(startDate, endDate)) {
//                    // 把日期添加到集合
//                    Date nDate = new Date(startDate.getTime());
//                    if (isWeekMatch(week,nDate)) {
//                        list.add(nDate);
//                    }
//                    // 获取增加后的日期
//                    startDate = offsetDay(startDate, -1);
//                }
//            }
//            if (!isIncludeStart) {
////                if (isEq(list.get(0),))
//                list.remove(0);
//            }
//            if (!isIncludeEnd) {
//                list.remove(list.size() - 1);
//            }
//        }
//        return list;
//    }


    private static boolean isWeekMatch(Week week,Date date){
        return week.getValue() == dayOfWeek(date);
    }


    // -------------------------------------------------------------------- Part of Date start

    /**
     * 获得日期的某个部分<br>
     * 例如获得年的部分，则使用 getField(DatePart.YEAR)
     *
     * @param date  日期
     * @param field 表示日期的哪个部分的枚举 {@link DateField}
     * @return 某个部分的值
     */
    private static int getField(Date date, DateField field) {
        return getField(date, field.getValue());
    }

    /**
     * 获得日期的某个部分<br>
     * 例如获得年的部分，则使用 getField(Calendar.YEAR)
     *
     * @param field 表示日期的哪个部分的int值 {@link Calendar}
     * @return 某个部分的值
     */
    private static int getField(Date date, int field) {
        return toCalendar(date).get(field);
    }


    /**
     * 转换为Calendar, 默认 {@link Locale}
     *
     * @return {@link Calendar}
     */
    private static Calendar toCalendar(Date date) {
        return toCalendar(date, Locale.getDefault(Locale.Category.FORMAT));
    }

    /**
     * 转换为Calendar
     *
     * @param locale 地域 {@link Locale}
     * @return {@link Calendar}
     */
    private static Calendar toCalendar(Date date, Locale locale) {
        return toCalendar(date, TimeZone.getDefault(), locale);
    }

    /**
     * 转换为Calendar
     *
     * @param zone   时区 {@link TimeZone}
     * @param locale 地域 {@link Locale}
     * @return {@link Calendar}
     */
    private static Calendar toCalendar(Date date, TimeZone zone, Locale locale) {
        if (null == locale) {
            locale = Locale.getDefault(Locale.Category.FORMAT);
        }
        final Calendar cal = (null != zone) ? Calendar.getInstance(zone, locale) : Calendar.getInstance(locale);
        // 设置每周的第一天为周日
        cal.setFirstDayOfWeek(Week.MONDAY.getValue());
        cal.setTime(date);
        return cal;
    }

    //*************************************  offset 时间偏移 ******************************************************//

    /**
     * 偏移毫秒数
     *
     * @param date   日期
     * @param offset 偏移毫秒数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetMillisecond(Date date, int offset) {
        return offset(date, DateField.MILLISECOND, offset);
    }

    /**
     * 偏移秒数
     *
     * @param date   日期
     * @param offset 偏移秒数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetSecond(Date date, int offset) {
        return offset(date, DateField.SECOND, offset);
    }

    /**
     * 偏移分钟
     *
     * @param date   日期
     * @param offset 偏移分钟数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetMinute(Date date, int offset) {
        return offset(date, DateField.MINUTE, offset);
    }

    /**
     * 偏移小时
     *
     * @param date   日期
     * @param offset 偏移小时数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetHour(Date date, int offset) {
        return offset(date, DateField.HOUR_OF_DAY, offset);
    }

    /**
     * w
     * 偏移天
     *
     * @param date   日期
     * @param offset 偏移天数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetDay(Date date, int offset) {
        return offset(date, DateField.DAY_OF_YEAR, offset);
    }

    /**
     * 偏移周
     *
     * @param date   日期
     * @param offset 偏移周数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetWeek(Date date, int offset) {
        return offset(date, DateField.WEEK_OF_YEAR, offset);
    }

    /**
     * 偏移月
     *
     * @param date   日期
     * @param offset 偏移月数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetMonth(Date date, int offset) {
        return offset(date, DateField.MONTH, offset);
    }

    /**
     * 调整日期和时间<br>
     *
     * @param date     日期
     * @param datePart 调整的部分 {@link DateField}
     * @param offset   偏移量，正数为向后偏移，负数为向前偏移
     * @return 如果此对象为可变对象，返回自身，否则返回新对象
     */
    public static Date offset(Date date, DateField datePart, int offset) {
        if (DateField.ERA == datePart) {
            throw new IllegalArgumentException("ERA is not support offset!");
        }

        final Calendar cal = toCalendar(date);
        //noinspection MagicConstant
        cal.add(datePart.getValue(), offset);
        date.setTime(cal.getTimeInMillis());
        return date;
    }

    //

    /**
     * 获取当前时间格式化后的时间
     *
     * @return 格式化的时间
     */
    public static String currentFmtDateStr(){
        return "";
    }

    // 获取今天的开始日期  2023-11-14 00:00:00
    // 获取今天的结束日期  2023-11-14 23:59:59
    // 日期字符串比较

}
